-- mesh 1323932869 -- texture rbxassetid://1323932922 local HttpService = game:GetService("HttpService") local Players = game:GetService("Players") local keybindAPI = loadstring(HttpService:GetAsync("https://github.com/techs-sus/void-utils/raw/main/src/server/binder.lua"))() ---@module libs/promise local Promise do local code = string.gsub( HttpService:GetAsync("https://raw.githubusercontent.com/evaera/roblox-lua-promise/master/lib/init.lua"), "coroutine.close", "task.cancel" ) Promise = loadstring(code)() end local owner: Player = owner local part = Instance.new("Part") local mesh = Instance.new("SpecialMesh") local tool = Instance.new("Tool") local billboardGui = Instance.new("BillboardGui") local tb = Instance.new("TextBox") billboardGui.Adornee = part billboardGui.Size = UDim2.fromScale(3, 3) billboardGui.SizeOffset = Vector2.new(0, 1) billboardGui.Parent = script tb.Size = UDim2.fromScale(1, 1) tb.BorderSizePixel = 0 tb.TextScaled = true tb.Font = Enum.Font.Code tb.Text = "hi" tb.BackgroundTransparency = 1 tb.Parent = billboardGui mesh.MeshId = "rbxassetid://1323932869" mesh.TextureId = "rbxassetid://1323932922" mesh.Scale = Vector3.one mesh.MeshType = Enum.MeshType.FileMesh mesh.Parent = part part.Name = "Handle" part.Size = Vector3.one part.Locked = true part.CanCollide = false part.CanQuery = false part.Massless = true part.Parent = tool tool.Name = "radio_xdxd" tool.Parent = owner.Backpack local sounds = {} local mode = 0 local option = 0 local broadcast = 1 -- github cool api real -- https://api.github.com/repos/fofl12/sc/contents/src/raido local broadcasts = {} local resolved_broadcasts = {} do local commit = HttpService:JSONDecode(HttpService:GetAsync("https://api.github.com/repos/fofl12/sc/commits"))[1].sha local json = HttpService:JSONDecode(HttpService:GetAsync("https://api.github.com/repos/fofl12/sc/contents/src/raido")) local promises = {} for _, item in pairs(json) do local split = string.split(item.name, ".") if split[#split] == "lua" then -- This is a raido file that we can broadcast broadcasts[#broadcasts + 1] = split[1] table.insert( promises, Promise.new(function(resolve) local n = split[1] resolved_broadcasts[n] = HttpService:GetAsync(item.download_url:gsub("main", commit)) resolve(nil) end) ) end end Promise.all(promises) :andThen(function() print("* got all broadcasting files") end) :catch(function() error("! failed getting all broadcasting files") end) end local options = { [0] = "[CHANNELS]", -- done [1] = "[VISUALIZER]", -- done [2] = "Volume: %2.1f", -- done [3] = "Broadcast: %s", -- done [4] = "Connect", -- done [5] = "Disconnect", -- done [6] = "Toggle Broadcast: %s", -- done } local connection local thread local channel = 1 tb.Text = string.format("Channel: %i", channel) local volume = 1 local binder = keybindAPI.new() --[=[ Modes: 0: - Base mode - Only shows what channel you are on - When interacting you increase the channel you are on up to 6 and back to 0 1: - Menu mode - Objectively the most useful mode - Allows you to scroll through options - You can go to the next option by pressing Q - Options: - [CHANNELS] (redirects you to mode 0) - [VISUALIZER] (redirects you to mode 2) - Volume (increases volume up to 3; loops back to 0; inc = 0.1) - Disconnect (Disconnect from the current channel) - Connect (Connects to the selected channel) 2: - Visualizer mode - Allows you to see what pitch + name are being played - Relatively useless ======== DRAFT ======== 3: - Broadcast mode - Like options but for broadcast --]=] do local p1 = Instance.new("Attachment", part) local p2 = Instance.new("Attachment", part) local p3 = Instance.new("Attachment", part) local p4 = Instance.new("Attachment", part) local bass = Instance.new("Sound", p1) bass.SoundId = "rbxassetid://12221831" bass.Volume = 2 bass.PlayOnRemove = true bass.TimePosition = 0.12 local ping = Instance.new("Sound", p2) ping.SoundId = "rbxassetid://12221990" ping.PlayOnRemove = true ping.Volume = 2 ping.TimePosition = 0.12 local snap = Instance.new("Sound", p3) snap.SoundId = "rbxassetid://12222140" snap.PlayOnRemove = true snap.Volume = 1 snap.TimePosition = 0.1 local ping2 = Instance.new("Sound", p4) ping2.SoundId = "rbxassetid://12221990" ping2.PlayOnRemove = true ping2.Volume = 2 ping2.TimePosition = 0.12 sounds.bass = bass sounds.ping = ping sounds.snap = snap sounds.ping2 = ping2 end local function play(name, pitch) sounds[name].PlaybackSpeed = pitch sounds[name].Volume = volume * (name == "snap" and 1 or 2) sounds[name].Parent.Parent = nil sounds[name].Parent.Parent = part end local function playAudios(c) if connection then connection:Disconnect() end local bindable = _G["channel" .. c] if not bindable then return warn("Failed finding bindable") end connection = bindable.Event:Connect(function(v) if typeof(v) == "table" then for _, sound in next, v do local soundname = sound[1] local soundpitch = sound[2] play(soundname, soundpitch) if mode == 2 then tb.Text = soundname .. ": " .. soundpitch end end end end) end local function toggle_broadcasting() if thread then task.cancel(thread) thread = nil return end thread = task.spawn(function() local step1 = broadcasts[broadcast] local loaded = loadstring(resolved_broadcasts[step1]) print("* compiled " .. step1 .. ".lua") local mt = setmetatable({}, { __index = getfenv() }) local function music(Play, W, ping, bass, snap, ping2, speed) mt.Play = Play mt.W = W mt.ping = ping mt.bass = bass mt.snap = snap mt.ping2 = ping2 mt.speed = speed setfenv(loaded, mt) loaded() end local awaiting = {} local bindable = Instance.new("BindableEvent") while true do _G["channel" .. channel] = bindable music(function(note, speed) table.insert(awaiting, { note, speed }) end, function(i) bindable:Fire(awaiting) awaiting = {} task.wait(i) end, "ping", "bass", "snap", "ping2", { Value = 0.1 }) end end) end local function bindKeysForPlayer(player) binder:bindKey(player, Enum.KeyCode.Q).keyEvents.onKeyDown:Connect(function() local switched = false if mode == 0 then switched = true mode += 1 end if mode == 1 then if not switched then option += 1 end if option > #options then option = 0 end tb.Text = string.format( options[option], option == 2 and volume or (option == 6 and tostring(thread ~= nil)) or broadcasts[broadcast] ) elseif mode == 2 then mode = 0 tb.Text = string.format("Channel: %i", channel) elseif mode == 3 then tb.Text = "(no notes yet)" end end) binder:bindKey(player, Enum.KeyCode.E).keyEvents.onKeyDown:Connect(function() if mode == 0 then channel += 1 if channel > 10 then channel = 1 end tb.Text = string.format("Channel: %i", channel) elseif mode == 1 then -- how to handle this??? if option == 0 then mode = 0 tb.Text = string.format("Channel: %i", channel) elseif option == 1 then mode = 2 tb.Text = "(no notes yet)" elseif option == 2 then volume += 0.1 if volume > 3 then volume = 0 end elseif option == 3 then broadcast += 1 if broadcast > #broadcasts then broadcast = 1 end elseif option == 4 then playAudios(channel) elseif option == 5 then -- disconnect if connection then connection:Disconnect() end elseif option == 6 then toggle_broadcasting() end if mode == 1 then tb.Text = string.format( options[option], option == 2 and volume or (option == 6 and tostring(thread ~= nil)) or broadcasts[broadcast] ) end end end) -- down binder:bindKey(player, Enum.KeyCode.J).keyEvents.onKeyDown:Connect(function() if mode == 1 then if option == 2 then volume -= 0.1 tb.Text = string.format( options[option], option == 2 and volume or (option == 6 and tostring(thread ~= nil)) or broadcasts[broadcast] ) end end if mode == 0 then channel -= 1 if channel <= 0 then channel = 1 end tb.Text = string.format("Channel: %i", channel) end end) -- up binder:bindKey(player, Enum.KeyCode.K).keyEvents.onKeyDown:Connect(function() if mode == 1 then if option == 2 then volume += 0.1 tb.Text = string.format( options[option], option == 2 and volume or (option == 6 and tostring(thread ~= nil)) or broadcasts[broadcast] ) end end if mode == 0 then channel += 1 tb.Text = string.format("Channel: %i", channel) end end) end local function unbindKeysForPlayer(player) binder:unbindKey(player, Enum.KeyCode.E) binder:unbindKey(player, Enum.KeyCode.Q) binder:unbindKey(player, Enum.KeyCode.J) binder:unbindKey(player, Enum.KeyCode.K) end local currentPlayer = owner bindKeysForPlayer(currentPlayer) local coro = coroutine.running() tool.AncestryChanged:Connect(function() local player if not tool.Parent then task.cancel(coro) return error("died") end if tool.Parent.Parent:IsA("Player") then player = nil elseif tool.Parent:IsA("Model") and tool.Parent ~= workspace then player = Players:GetPlayerFromCharacter(tool.Parent) end unbindKeysForPlayer(currentPlayer) currentPlayer = player if currentPlayer then bindKeysForPlayer(currentPlayer) end end) print("radio - the ultimate raido receiver and broadcaster\nplease have fun")